package com.jinly.ryder.account.web.utils;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.jinly.ryder.account.service.UserAuthService;
import com.jinly.ryder.common.auth.LoginContent;
import com.jinly.ryder.common.auth.model.AuthInfo;
import com.jinly.ryder.common.auth.model.AuthRole;
import com.jinly.ryder.common.auth.model.AuthType;
import com.jinly.ryder.common.error.SystemErrorType;
import com.jinly.ryder.common.utils.SpringContextUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class AuthUtil {

    private static Cache<String, List<AuthInfo>> userAuthCache = Caffeine.newBuilder()
            .expireAfterWrite(1, TimeUnit.MINUTES)
            .initialCapacity(100)
            .maximumSize(1000)
            .build();

    public static void check(AuthType type, String authData, AuthRole role) {
        if (hasAuth(AuthType.MANAGE, "admin", AuthRole.ADMIN)) return;
        if (!hasAuth(type, authData, role))
            SystemErrorType.FORBIDDEN.throwError();
    }

    public static boolean hasAuth(AuthType type, String authData, AuthRole role) {
        Long userId = LoginContent.getUserId();
        if (userId == null || ObjectUtils.isEmpty(authData)) return false;
        List<AuthInfo> authInfoList = getUserAuthList(userId, type);
        for (AuthInfo userAuthInfo : authInfoList) {
            if (ObjectUtils.nullSafeEquals(authData, userAuthInfo.getAuthData())) {
                if (role.ordinal() >= userAuthInfo.getAuthRole().ordinal()) {
                    return true;
                }
            }
        }
        return false;
    }

    private static List<AuthInfo> getUserAuthList(Long userId, AuthType type) {
        UserAuthService userAuthService = SpringContextUtil.getBean(UserAuthService.class);
        return userAuthCache.get(userId + "_" + type.name(), key ->
                userAuthService.queryUserAuthListByUserId(userId, type).stream().map(a -> {
                    AuthInfo authInfo = new AuthInfo();
                    BeanUtils.copyProperties(a, authInfo);
                    return authInfo;
                }).collect(Collectors.toList())
        );
    }

    public static boolean isSuperAdmin() {
        return hasAuth(AuthType.MANAGE, "admin", AuthRole.ADMIN);
    }
}
